package cn.bincker.mybatis.encrypt.type;

import cn.bincker.mybatis.encrypt.core.EncryptExecutor;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.*;
import java.util.Date;

public class EncryptTypeHandlerConfigurator {
    public static void configure(Configuration configuration, EncryptExecutor encryptExecutor){
        var registry = configuration.getTypeHandlerRegistry();
        var handler = new EncryptByteArrayTypeHandler<>();
        registerEncryptType(registry, Boolean.class, handler);
        registerEncryptType(registry, boolean.class, handler);

        registerEncryptType(registry, Byte.class, handler);
        registerEncryptType(registry, byte.class, handler);

        registerEncryptType(registry, Short.class, handler);
        registerEncryptType(registry, short.class, handler);

        registerEncryptType(registry, Integer.class, handler);
        registerEncryptType(registry, int.class, handler);

        registerEncryptType(registry, Long.class, handler);
        registerEncryptType(registry, long.class, handler);

        registerEncryptType(registry, Float.class, handler);
        registerEncryptType(registry, float.class, handler);

        registerEncryptType(registry, Double.class, handler);
        registerEncryptType(registry, double.class, handler);

//        registry.register(Reader.class, JdbcType.BINARY, new EncryptByteArrayTypeHandler<>());
        registerEncryptType(registry, String.class, handler);


        registerEncryptType(registry, BigInteger.class, handler);

        registerEncryptType(registry, BigDecimal.class, handler);

//        registry.register(InputStream.class, JdbcType.BINARY, new EncryptByteArrayTypeHandler<>());
//        registry.register(Byte[].class, JdbcType.BINARY, new EncryptByteArrayTypeHandler<>());
//        registry.register(byte[].class, JdbcType.BINARY, new EncryptByteArrayTypeHandler<>());


        registerEncryptType(registry, Date.class, handler);

        registerEncryptType(registry, java.sql.Date.class, handler);
        registerEncryptType(registry, java.sql.Time.class, handler);
        registerEncryptType(registry, java.sql.Timestamp.class, handler);


        registerEncryptType(registry, Instant.class, handler);
        registerEncryptType(registry, LocalDateTime.class, handler);
        registerEncryptType(registry, LocalDate.class, handler);
        registerEncryptType(registry, LocalTime.class, handler);
        registerEncryptType(registry, OffsetDateTime.class, handler);
        registerEncryptType(registry, OffsetTime.class, handler);
        registerEncryptType(registry, ZonedDateTime.class, handler);
        registerEncryptType(registry, Month.class, handler);
        registerEncryptType(registry, Year.class, handler);
        registerEncryptType(registry, YearMonth.class, handler);

        registry.register(EncryptParam.class, new EncryptParamTypeHandler<>(encryptExecutor));
    }

    @SuppressWarnings("unchecked")
    private static <T> void registerEncryptType(TypeHandlerRegistry registry, Class<T> type, EncryptByteArrayTypeHandler<?> handler) {
        registry.register(type, JdbcType.BINARY, (TypeHandler<? extends T>) handler);
        registry.register(type, JdbcType.VARBINARY, (TypeHandler<? extends T>) handler);
        registry.register(type, JdbcType.LONGVARBINARY, (TypeHandler<? extends T>) handler);
        registry.register(type, JdbcType.BLOB, (TypeHandler<? extends T>) handler);
    }
}
